/**
 * This file is part of 1genia trampoline
 * Copyright (C) 2007 1genia (contact@1genia.com)
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; version 3 of the License. 
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details. 
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; see the file COPYING.TXT.  If not,
 * write to the Free Software Foundation, Inc., 51 Franklin Street,
 * Fifth Floor, Boston, MA 02110-1301, USA. 
 **/
package com.genia.toolbox.web.filter;

import java.io.IOException;
import java.util.Iterator;
import java.util.List;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

/**
 * the <code>Filter</code> that handles <code>CustomFilter</code>. It
 * should be instanciated through a <code>DelegatingFilterProxy</code> to be
 * injected its dependencies.
 */
public class GenericFilter
    implements Filter
{

  /**
   * the list of <code>CustomFilter</code> to handle.
   */
  private List<CustomFilter> filters = null;

  /**
   * a custom implementation of <code>FilterChain</code> that pass through
   * each filter of the list <code>filters</code>, and then delegate the
   * query to the original <code>FilterChain</code>.
   */
  private class CustomChain
      implements FilterChain
  {

    /**
     * the original <code>FilterChain</code>.
     */
    private transient final FilterChain originalChain;

    /**
     * the iterator that handle the list of <code>CustomFilter</code>.
     */
    private transient final Iterator<CustomFilter> filterIterator;



    /**
     * Constructor.
     * 
     * @param originalChain
     *          the original <code>FilterChain</code>
     * @param filterIterator
     *          the iterator that handle the list of <code>CustomFilter</code>
     */
    public CustomChain(final FilterChain originalChain, final Iterator<CustomFilter> filterIterator)
    {
      this.originalChain = originalChain;
      this.filterIterator = filterIterator;
    }



    /**
     * Causes the next filter in the chain to be invoked, or if the calling
     * filter is the last filter in the chain, causes the resource at the end of
     * the chain to be invoked.
     * 
     * @param request
     *          the request to pass along the chain
     * @param response
     *          the response to pass along the chain
     * @throws IOException
     *           when an error occurred
     * @throws ServletException
     *           when an error occurred
     * @see javax.servlet.FilterChain#doFilter(javax.servlet.ServletRequest,
     *      javax.servlet.ServletResponse)
     */
    public void doFilter(final ServletRequest request, final ServletResponse response)
        throws IOException, ServletException
    {
      if (filterIterator.hasNext()) {
        filterIterator.next().doFilter(request, response, this);
      }
      else {
        originalChain.doFilter(request, response);
      }
    }
  }



  /**
   * Called by the web container to indicate to a filter that it is being taken
   * out of service. This implementation does nothing.
   * 
   * @see javax.servlet.Filter#destroy()
   */
  public void destroy()
  {
    for (final Filter filter : getFilters()) {
      filter.destroy();
    }
  }



  /**
   * The <code>doFilter</code> method of the Filter is called by the container
   * each time a request/response pair is passed through the chain due to a
   * client request for a resource at the end of the chain. The FilterChain
   * passed in to this method allows the Filter to pass on the request and
   * response to the next entity in the chain.
   * 
   * @param request
   *          the request to pass along the chain
   * @param response
   *          the response to pass along the chain
   * @param chain
   *          the <code>FilterChain</code> use to pass the request to the next
   *          <code>Filter</code>
   * @throws IOException
   *           when an error occurred
   * @throws ServletException
   *           when an error occurred
   * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest,
   *      javax.servlet.ServletResponse, javax.servlet.FilterChain)
   */
  public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
      throws IOException, ServletException
  {
    new CustomChain(chain, getFilters().iterator()).doFilter(request, response);
  }



  /**
   * Called by the web container to indicate to a filter that it is being placed
   * into service. This implementation does nothing.
   * 
   * @param config
   *          the configuration of this filter.
   * @throws ServletException
   *           when an error occurred.
   * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
   */
  public void init(final FilterConfig config)
      throws ServletException
  {
    for (final Filter filter : getFilters()) {
      filter.init(config);
    }
  }



  /**
   * getter for the filters property.
   * 
   * @return the filters
   */
  public List<CustomFilter> getFilters()
  {
    return filters;
  }



  /**
   * setter for the filters property.
   * 
   * @param filters
   *          the filters to set
   */
  public void setFilters(List<CustomFilter> filters)
  {
    this.filters = filters;
  }

}
